########################################################################
#  Searx-qt - Lightweight desktop application for SearX.
#  Copyright (C) 2020  CYBERDEViL
#
#  This file is part of Searx-qt.
#
#  Searx-qt is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  Searx-qt is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <https://www.gnu.org/licenses/>.
#
########################################################################


import html
from urllib.parse import quote

from searxqt.utils.string import formatFileSize, formatFileCount
from searxqt.translations import _


class HtmlGen:
    def wrapHtml(bodyStr, styleStr=""):
        return """
<html>
  <head>
    <style>{style}</style>
  </head>
  <body>
    {body}
  </body>
</html>""".format(body=bodyStr, style=styleStr)


class FailedResponseHtml:
    def create(result, css):
        """
        @param result: Failed search result object.
        @type result: searxqt.core.requests.Result

        @param css: Optionaly set a stylesheet, it should be the content only;
                    so do not include the <style> tags!
        @type css: str
        """

        return HtmlGen.wrapHtml("""<h3>Search failed.</h3>
<h4>Instance:</h4>
<p>{url}</p>
<h4>Error:</h4>
<p>{errMsg}</p>
<h4>Response content:</h4>
<p>{text}</p>""".format(
                url=result.url(),
                errMsg=html.escape(result.error()),
                text=html.escape(result.text()),
            ),
            css
        )


class ResultsHtml:
    """ Create HTML from a valid search response.
    """

    def create(jsonResult, css):
        """
        @param jsonResult: The josn result of a search response.
        @type jsonResult: json or dict

        @param css: Optionaly set a stylesheet, it should be the content only;
                    so do not include the <style> tags!
        @type css: str
        """
        elemStr = ""

        # Search query suggestions
        data = jsonResult.get('suggestions', [])
        if data:
            elemStr += ResultsHtml.createHrefListElement(
                'search', _('Suggestions'), data
            )
            elemStr += "<hr>"

        # Search query corrections
        data = jsonResult.get('corrections', [])
        if data:
            elemStr += ResultsHtml.createHrefListElement(
                'search', _('Corrections'), data
            )
            elemStr += "<hr>"

        # Unresponsive engines
        data = jsonResult.get('unresponsive_engines', [])
        if data:
            elemStr += ResultsHtml.createUnresponsiveEnginesElement(data)
            elemStr += "<hr>"

        # Infoboxes
        data = jsonResult.get('infoboxes', [])
        if data:
            elemStr += "<p id=\"infoboxes_header\">Infoboxes</p>"
            for infoboxData in data:
                elemStr += ResultsHtml.createInfobox(infoboxData)

        # Answers
        data = jsonResult.get('answers', [])
        if data:
            elemStr += ResultsHtml.createStrListElement(_('Answers'), data)
            elemStr += "<hr>"

        # Results
        data = jsonResult.get('results', [])
        if data:
            for resultData in data:
                elemStr += ResultsHtml.createResultElement(resultData)

        return HtmlGen.wrapHtml(elemStr, css)

    def createStrListElement(title, data):
        elemStr = " | ".join([html.escape(entry) for entry in data])
        return ResultsHtml.createListContainer(title, elemStr)

    def createHrefListElement(scheme, title, data):
        elemStr = ""
        scheme += ":"
        for entry in data:
            if elemStr:
                elemStr += " | "
            url = scheme + quote(entry)
            elemStr += "<a href=\"{0}\">{1}</a>".format(url, html.escape(entry))
        return ResultsHtml.createListContainer(title, elemStr)

    def createListContainer(title, elems):
        return """<div class=\"{0}\"><b>{0}</b>: {1}</div>
        """.format(title, elems)

    def createUnresponsiveEnginesElement(data):
        elemStr = ""
        for name, error in data:
            if elemStr:
                elemStr += " | "
            elemStr += "{0} <i>({1})</i>".format(
                html.escape(name),
                html.escape(error)
            )
        return ResultsHtml.createListContainer(_('Unresponsive engines'), elemStr)

    def createInfobox(infoboxData):
        # Create new infobox
        elemStr = "<div class=\"infobox\">"

        # Title
        elemStr += "<center><div class=\"infobox_title\">{}</div></center>".format(
            html.escape(infoboxData.get("infobox", "-"))
        )

        # ID
        data = infoboxData.get("id", None)
        if data:
            elemStr += "<center><div class=\"infobox_id\"><a href=\"{0}\">{0}</a></div></center>".format(
                html.escape(data)
            )

        # Content
        data = infoboxData.get("content", None)
        if data:
            elemStr += "<div class=\"infobox_content\">{}</div>".format(html.escape(data))

        # Attributes
        data = infoboxData.get("attributes", None)
        if data:
            elemStr += "<p class=\"infobox_attr_head\">Attributes</p>"
            elemStr += "<table class=\"infobox_attr_table\">"
            for attributeData in data:
                # TODO for now skip images ..
                if "value" not in attributeData:
                    continue

                # New row
                elemStr += "<tr>"
                elemStr += "<td class=\"infobox_label\">{0}</td>".format(
                    html.escape(attributeData.get('label', ''))
                )
                elemStr += "<td class=\"infobox_value\">{0}</td>".format(
                    html.escape(attributeData.get('value', ''))
                )
                elemStr += "</tr>"
            elemStr += "</table>"

        # Urls list
        data = infoboxData.get("urls", None)
        if data:
            elemStr += "<p class=\"infobox_links_head\">Links</p>"
            elemStr += "<ul class=\"infobox_link_list\">"
            for urlData in data:
                elemStr += ("<li class=\"infobox_link_list_item\">"
                            "<a href=\"{0}\" title=\"{0}\">{1}</a></li>"
                ).format(
                    html.escape(urlData.get("url")),
                    html.escape(urlData.get("title", "-"))
                )
            elemStr += "</ul>"

        # Engines
        data = infoboxData.get("engines", None)
        if data:
            elemStr += ResultsHtml.createStrListElement(_('Engines'), data)

        # Closing tag of the new infobox element.
        elemStr += "</div>"
        elemStr += "<hr>"

        return elemStr

    def createResultElement(data):
        # Create general elements
        elemStr = """<div class="results">
<h4 class="result-title"><i>{engine}: </i><a href="{url}">{title}</a></h4>
<div style="margin-left: 10px;">
  <p class="result-description">{content}</p>
  <p class="result-url">{url}</p>""".format(
            title=html.escape(data.get('title', '')),
            url=html.escape(data.get('url', '')),
            content=html.escape(data.get('content', '')),
            engine=html.escape(data.get('engine', '?'))
        )

        # Add file data elements
        elemStr += ResultsHtml.createFileSection(data)

        elemStr += "</div></div>"
        return elemStr

    def createFileSection(data):
        elemStr = ""

        if data.get('magnetlink', ''):
            elemStr += "<a href=\"{0}\">Magnet</a> ".format(
                html.escape(data['magnetlink'])
            )

        if data.get('torrentfile', ''):
            elemStr += "<a href=\"{0}\">Torrent</a> ".format(
                html.escape(data['torrentfile'])
            )

        if data.get('filesize', 0):
            elemStr += formatFileSize(data['filesize']) + " "

        if data.get('files', 0):
            elemStr += formatFileCount(data['files']) + " "

        if data.get('seed', None) is not None:
            elemStr += "seeders: {0} ".format(data['seed'])

        if data.get('leech', None) is not None:
            elemStr += "leechers: {0} ".format(data['leech'])

        if data.get('img_format', ""):
            elemStr += "format: {0} ".format(
                html.escape(data['img_format'])
            )

        if elemStr:
            elemStr = "<p class=\"result-file\">" + elemStr + "</p>"

        return elemStr
